/********************************************
*
*
********************************************/


#ifdef __cplusplus
 #if __cplusplus
  extern "C"{
 #endif
#endif /* __cplusplus */

#include "ats.h"
#include "pthread.h"

#define ATS_COND_INCLUDE 1
#define ATS_COND_EXCLUDE 0

#define ATS_COND_SORT    2
#define ATS_COND_MIX     0

ATS_CTL stAtsCtl;

#define ATS_LOCK()       pthread_mutex_lock(&stAtsCtl.stLock)
#define ATS_UNLOCK()     pthread_mutex_unlock(&stAtsCtl.stLock)

#define ATS_LOG  printf

UINT32 ATS_ShowHook(UINT32 uiDir, CHAR * pcString, UINT32 uiStrLen)
{
    ATS_LOCK();
    if( uiStrLen >= ( stAtsCtl.ulBufflength - stAtsCtl.ulBuffUsedLen ))
    {
        ATS_UNLOCK();
        ATS_LOG("\r\nATS_ShowHook failed! buff length(%u) is not enough!\r\n",
                stAtsCtl.ulBufflength - stAtsCtl.ulBuffUsedLen);
        return DMS_OK;
    }

    memcpy(stAtsCtl.pJudgebuff + stAtsCtl.ulBuffUsedLen ,pcString,uiStrLen);
    stAtsCtl.ulBuffUsedLen += uiStrLen;
    stAtsCtl.pJudgebuff[stAtsCtl.ulBuffUsedLen] = '\0';

    if(stAtsCtl.ulIsPrint)
    {
        write(1,pcString,uiStrLen);
    }

    ATS_UNLOCK();
    return DMS_OK;
}

VOID DMS_ShowDirHookSet(DMS_SHOW_DIR_HOOK_FUNC pfuncAdd);


UINT32 ATS_Init()
{
    UINT32 ulRet;

	ulRet = pthread_mutex_init(&stAtsCtl.stLock,NULL);
	if(DMS_OK != ulRet)
	{
		return DMS_MUTEX_FAILED;
	}

	DMS_LIST_INIT(&stAtsCtl.stHead);

	stAtsCtl.pJudgebuff   = NULL;
	stAtsCtl.ulBufflength = 0;
	stAtsCtl.ulEnable     = DMS_FALSE;
    stAtsCtl.ulJudgeType  = 0;
    stAtsCtl.ulIsPrint    = DMS_TRUE;

    return DMS_OK;
}

UINT32 ATS_Fini()
{
    return DMS_OK;
}

UINT32 ATS_Begin(UINT32 ulJudgeType ,UINT32 ulBuffLength , UINT32 ulIsPrint)
{
    if(0 == ulBuffLength)
    {
        ATS_LOG("\r\nATS_Begin failed! ulBuffLength must be lager zero!\r\n");
        return DMS_ERR;
    }

    if( (ATS_JUDGE_SORT | ATS_JUDGE_OR) < ulJudgeType)
    {
        ATS_LOG("\r\nATS_Begin failed! ulJudgeType must be latter 0x11 !\r\n");
        return DMS_ERR;
    }

    ATS_LOCK();
    if(NULL != stAtsCtl.pJudgebuff)
    {
        ATS_UNLOCK();
        ATS_LOG("\r\nATS_Begin failed! Please ATS_Judge or ATS_Init first!\r\n");
        return DMS_ERR;
    }

    stAtsCtl.pJudgebuff = malloc(ulBuffLength);
    if(NULL == stAtsCtl.pJudgebuff)
    {
        ATS_UNLOCK();
        ATS_LOG("\r\nATS_Begin failed! malloc size(%u) failed!\r\n",ulBuffLength);
        return DMS_ERR;
    }

    stAtsCtl.ulIsPrint     = ( ulIsPrint > 0 ) ? DMS_TRUE : DMS_FALSE;

    stAtsCtl.ulBufflength  = ulBuffLength;
    stAtsCtl.ulJudgeType   = ulJudgeType;
    stAtsCtl.ulBuffUsedLen = 0;
    stAtsCtl.ulEnable     = DMS_TRUE;

    stAtsCtl.pfnShowHookBackup = DMS_ShowDirHookGet();
    DMS_ShowDirHookSet(ATS_ShowHook);

    ATS_UNLOCK();
    return DMS_OK;
}

UINT32 ATS_Cond(UINT32 ulCondType, UINT32 ulCount, const char * format , ...)
{
    CHAR       acbuffer[DMS_MAX_FORMAT_LEN + 10];
    va_list    argptr;
    int        cnt;
    ATS_COND * pstAtsCond;

    if((ATS_COND_INCLUDE != ulCondType ) && (ATS_COND_EXCLUDE != ulCondType ))
    {
        ATS_LOG("\r\nATS_Cond failed! ulCondType is invalid!\r\n");
        return DMS_INVALID_PARAM;
    }

    if( NULL == format )
    {
        ATS_LOG("\r\nATS_Cond failed! format is invalid!\r\n");
        return DMS_INVALID_PARAM;
    }

    va_start(argptr, format);
    cnt = vsnprintf(acbuffer,DMS_MAX_FORMAT_LEN + 10,format, argptr);
    va_end(argptr);

    if( DMS_MAX_FORMAT_LEN <= cnt )
    {
        ATS_LOG("\r\nATS_Cond failed! format length is too long!\r\n");
        return DMS_INVALID_PARAM;
    }

    ATS_LOCK();
    if(DMS_FALSE == stAtsCtl.ulEnable)
    {
        ATS_UNLOCK();
        ATS_LOG("\r\nATS_Cond failed! Please ATS_Begin first!\r\n");
        return DMS_ERR;
    }

    pstAtsCond = malloc(sizeof(ATS_COND));
    if(NULL == pstAtsCond)
    {
        ATS_UNLOCK();
        ATS_LOG("\r\nATS_Cond failed! malloc size(%u) failed!\r\n",sizeof(ATS_COND));
        return DMS_ERR;
    }

    pstAtsCond->ulCount    = ulCount;
    pstAtsCond->ulCondType = ulCondType;

    strncpy(pstAtsCond->acString, acbuffer, DMS_MAX_FORMAT_LEN);

    DMS_LIST_ADD_BEFORE( &(pstAtsCond->stNode), &(stAtsCtl.stHead) );

    ATS_UNLOCK();
    return DMS_OK;
}

UINT32 ATS_Judge(VOID)
{
    UINT32     ulJudgeType;
    UINT32     i;
    UINT32     ulSuccessCount = 0;
    UINT32     ulFailedCount  = 0;
    UINT32     ulRet;

    UINT32  ulBuffUsedLen;
    UINT32  ulFindCount;
    UINT32  ulCondLength;
    UINT32  ulBuffOffset;

    ATS_COND * pstATSCond;

    DMS_LIST_NODE * pstItem;
    DMS_LIST_NODE * pstTemp;
    DMS_LIST_NODE * pstHead;

    char *  pcBuffTemp;
    char *  pcTemp;
    const char *  pstring;

    ATS_LOCK();
    if(DMS_FALSE == stAtsCtl.ulEnable)
    {
        ATS_UNLOCK();
        ATS_LOG("\r\nATS_Cond failed! Please ATS_Begin and ATS_Cond first!\r\n");
        return DMS_ERR;
    }

    ulJudgeType = stAtsCtl.ulJudgeType ;
    pstHead     = &stAtsCtl.stHead;
    pcBuffTemp  = stAtsCtl.pJudgebuff;

    ulBuffUsedLen = stAtsCtl.ulBuffUsedLen;

    if(stAtsCtl.ulIsPrint)
    {
        ATS_LOG("\r\n%s\r\n",DMS_STR_ASTE_60);
        ATS_LOG("This Judge type is [%s] " ,( stAtsCtl.ulJudgeType & ATS_JUDGE_SORT ? "SORT":"MIX") );
        ATS_LOG("and [%s]\r\n" , (stAtsCtl.ulJudgeType & ATS_JUDGE_OR ? "OR" : "AND" ));
    }

    ulBuffOffset = 0;
    i = 0;

    DMS_LIST_TRAVERSAL(pstItem, pstHead)
    {
        if(!(stAtsCtl.ulJudgeType & ATS_JUDGE_SORT))
        {
            ulBuffOffset = 0;
        }

        ulFindCount   = 0;
        pstATSCond    = DMS_LIST_OFFSET(pstItem, ATS_COND, stNode);
        ulCondLength  = strlen(pstATSCond->acString);

        while(1)
        {
            if(ulBuffOffset >= stAtsCtl.ulBuffUsedLen )
            {
                break;
            }

            pcTemp = strstr( pcBuffTemp + ulBuffOffset, pstATSCond->acString);
            if(pcTemp)
            {
                ulBuffOffset = pcTemp - pcBuffTemp + ulCondLength;
                ulFindCount++;
            }
            else
            {
                break;
            }
        }

        if(ulFindCount)
        {
            if(ATS_COND_EXCLUDE == pstATSCond->ulCondType)
            {
                pstring = "but it should not be found!";

                if(pstATSCond->ulCount <= ulFindCount )
                {
                    ulFailedCount++;
                }
                else
                {
                    ulSuccessCount++;
                }
            }
            else
            {
                if(pstATSCond->ulCount <= ulFindCount )
                {
                    ulSuccessCount++;
                }
                else
                {
                    ulFailedCount++;
                }
                pstring = "";
            }

            if(stAtsCtl.ulIsPrint)
            {
                ATS_LOG("\r\nNo.%u ,this Cond has been found count %u. %s \r\n"
                        "%s\r\n",i,ulFindCount,pstring,pstATSCond->acString);
            }
        }
        else
        {
            if(ATS_COND_INCLUDE == pstATSCond->ulCondType)
            {
                pstring = "But it should be found!";
                ulFailedCount++;
            }
            else
            {
                pstring = "";
                ulSuccessCount++;
            }

            if(stAtsCtl.ulIsPrint)
            {
                ATS_LOG("\r\nNo.%u ,this Cond has been not found. %s \r\n"
                        "%s\r\n",i,pstring,pstATSCond->acString);
            }
        }
        i++;
    }

    DMS_LIST_TRAVERSAL_REMOVE(pstItem, pstTemp, pstHead)
    {
        pstATSCond    = DMS_LIST_OFFSET(pstItem, ATS_COND, stNode);
        free(pstATSCond);
    }

    if(ATS_JUDGE_OR & stAtsCtl.ulJudgeType)
    {
        if(ulSuccessCount)
        {
            ulRet = DMS_OK;
        }
        else
        {
            ulRet = DMS_ERR;
        }
    }
    else
    {
        if(ulFailedCount)
        {
            ulRet = DMS_ERR;
        }
        else
        {
            ulRet = DMS_OK;
        }
    }

    free(stAtsCtl.pJudgebuff);
    stAtsCtl.pJudgebuff = NULL;

    stAtsCtl.ulBufflength  = 0;
    stAtsCtl.ulBuffUsedLen = 0;
    stAtsCtl.ulEnable      = DMS_FALSE;
    stAtsCtl.ulIsPrint     = DMS_TRUE;
    stAtsCtl.ulJudgeType   = 0;

    DMS_ShowDirHookSet(stAtsCtl.pfnShowHookBackup);

    if(stAtsCtl.ulIsPrint)
    {
        ATS_LOG("%s\r\n",DMS_STR_ASTE_60);
    }

    return ulRet;
}

